package com.binarysnobbery.ymmv.client;

import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
//import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.datepicker.client.DateBox;


/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class MileageTracker implements EntryPoint {
	private VerticalPanel mainPanel = new VerticalPanel();
	private FlexTable mileageTable = new FlexTable();
	private HorizontalPanel mileageEntryPanel = new HorizontalPanel();
	private DateBox dateBox = new DateBox();
	private TextBox mileageInput = new TextBox();
	private TextBox gallonInput = new TextBox();
	private Button addButton = new Button("Add");
	private Label errorMsgLabel = new Label();
	private int rows = 1;
	private TrackerServiceAsync trackerSvc = GWT.create(TrackerServiceAsync.class);
	
	public void onModuleLoad() {
		// Setup the mileage table.
		mileageTable.addStyleName("mileageTable");
		mileageTable.setText(0, 0, "Date");
		mileageTable.setText(0, 1, "Miles");
		mileageTable.setText(0, 2, "Gallons");
		mileageTable.setText(0, 3, "MPG");
		mileageTable.setCellPadding(4);
		
		mileageTable.getRowFormatter().addStyleName(0, "mileageTableHeader");
		mileageTable.getCellFormatter().addStyleName(0, 0, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(0, 1, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(0, 2, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(0, 3, "numericColumn");
		
		loadEntries();
		
		// Setup the data entry row
		dateBox.setFormat(new DateBox.DefaultFormat(DateTimeFormat.getShortDateFormat()));
		dateBox.setValue(new Date());
		dateBox.addStyleName("numericColumn");
		mileageInput.addStyleName("numericColumn");
		mileageInput.setText("Miles");
		mileageInput.setFocus(true);
		mileageInput.addClickHandler(new ClickToClearText(mileageInput));
		mileageInput.setSelectionRange(0, mileageInput.getText().length());
		mileageInput.addKeyPressHandler(new KeyPressHandler() {
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					addMileageEntry();
				}	
			}
		});
		gallonInput.addStyleName("numericColumn");
		gallonInput.setText("Gallons");
		gallonInput.addClickHandler(new ClickToClearText(gallonInput));
		gallonInput.addKeyPressHandler(new KeyPressHandler() {
			@Override
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					addMileageEntry();
				}	
			}	
		});
		
		mileageEntryPanel.add(dateBox);
		mileageEntryPanel.add(mileageInput);
		mileageEntryPanel.add(gallonInput);
		mileageEntryPanel.add(addButton);
		
		// Assemble the main panel.
		errorMsgLabel.setStyleName("errorMessage");
		errorMsgLabel.setVisible(false);
		
		mainPanel.add(errorMsgLabel);
		mainPanel.add(mileageTable);
		mainPanel.add(mileageEntryPanel);
		
		// Associate mainPanel with HTML element
		RootPanel.get("mileagePanel").add(mainPanel);
		
		// Setup button event for addButton
		addButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				try {
					addMileageEntry();
					mileageInput.setText("Miles");
					gallonInput.setText("Gallons");
					errorMsgLabel.setVisible(false);
				} catch (NumberFormatException e) {
					errorMsgLabel.setText("Please enter a valid number for mileage and gallon input.");
					errorMsgLabel.setVisible(true);
				}
			}
		});
		
	}

	protected void addMileageEntry() throws NumberFormatException {
		final Date date = dateBox.getValue();
		String gallonsString = gallonInput.getValue();
		String milesString = mileageInput.getValue();
		double gallons, miles;
		
		gallons = Double.parseDouble(gallonsString);
		miles = Double.parseDouble(milesString);
		
		if (gallons > 99 || miles > 1000) {
			return;
		}
		
		addMileageEntry(date, gallons, miles);
	}
	
	private void addMileageEntry(final Date date, final double gallons, final double miles) {
		trackerSvc.addMileageEntry(date, gallons, miles, new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
				
			}
			public void onSuccess(Void ignore) {
				addMileageTableRow(date, gallons, miles);
			}
		});
	}
	
	protected void addMileageTableRow(Date dateStamp, double gallons, double miles) {
		mileageTable.setText(rows, 0, DateTimeFormat.getShortDateFormat().format(dateStamp));
		mileageTable.setText(rows, 1, formatShortNumeric(miles));
		mileageTable.setText(rows, 2, formatShortNumeric(gallons));
		mileageTable.setText(rows, 3, formatShortNumeric(miles / gallons));
		mileageTable.getCellFormatter().addStyleName(rows, 0, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(rows, 1, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(rows, 2, "numericColumn");
		mileageTable.getCellFormatter().addStyleName(rows, 3, "numericColumn");
		rows++;
	}
	
	private String formatShortNumeric(double d) {
		return NumberFormat.getFormat("#,###.##").format(d);
	}
	
	private class ClickToClearText implements ClickHandler {
		private TextBox box;
		
		public ClickToClearText(TextBox box) {
			this.box = box;
		}
		
		@Override
		public void onClick(ClickEvent event) {
			box.setText("");
		}
		
	}
	
	private void loadEntries() {
		trackerSvc.getEntries(new AsyncCallback<MileageEntry[]>() {
			public void onFailure(Throwable error) {
				
			}
			public void onSuccess(MileageEntry[] entries) {
				displayEntries(entries);
			}
		});
	}
	
	private void displayEntries(MileageEntry[] entries) {
		for (MileageEntry entry : entries) {
			addMileageTableRow(entry.getDate(), entry.getGallons(), entry.getMiles());
		}
	}
}
